package com.wxit.algorithm.block;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 两把锁
 * @param <E>
 */
@SuppressWarnings("all")
public class BlockingQueue2<E> implements BlockingQueue<E> {

    private E[] array;
    private int head;
    private int tail;
    private AtomicInteger size = new AtomicInteger();

    private ReentrantLock tailLock = new ReentrantLock();
    private Condition tailWaits = tailLock.newCondition();

    private ReentrantLock headLock = new ReentrantLock();
    private Condition headWaits = tailLock.newCondition();

    public BlockingQueue2(int capacity) {
        array = (E[]) new Object[capacity];
    }

    private boolean isEmpty() {
        return size.get() == 0;
    }

    private boolean isFull() {
        return size.get() == array.length;
    }

    @Override
    public void offer(E e) throws InterruptedException {
        tailLock.lockInterruptibly();
        try {
            // 1 满了要做的事情
            while (isFull()) {
                tailWaits.await();
            }
            // 2 不满，则入队
            array[tail] = e;
            if (++tail == array.length) {
                tail = 0;
            }

            // 修改size
            size.getAndIncrement();

        } finally {
            tailLock.unlock();
        }
    }

    @Override
    public boolean offer(E e, long timeout) throws InterruptedException {
        return false;
    }

    @Override
    public E poll() throws InterruptedException {
        headLock.lockInterruptibly();
        try {
            // 1 队列空则等待
            while (isEmpty()) {
                headWaits.await();
            }

            // 2 非空则出队
            E e = array[head];
            array[head] = null;
            if (++head == array.length) {
                head = 0;
            }
            // 修改size
            size.getAndDecrement();
        } finally { 
            headLock.unlock();
        }
        return null;
    }

    public static void main(String[] args) throws InterruptedException {
        BlockingQueue2 queue = new BlockingQueue2<>(100);
        queue.offer("任务1");

        new Thread(() -> {
            try {
                queue.offer("任务2");
            } catch (InterruptedException e) {
                throw  new RuntimeException(e);
            }
        }, "offer").start();

        new Thread(() -> {
            try {
                System.out.println(queue.poll());
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }, "poll").start();
    }
}
